package com.lin.cloud.disk.filter;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.lin.cloud.disk.common.constant.HttpConstant;
import com.lin.cloud.disk.common.constant.RedisConstant;
import com.lin.cloud.disk.common.exception.BusinessException;
import com.lin.cloud.disk.entity.dto.UserDTO;
import com.lin.cloud.disk.shiro.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

/**
 * token过滤器
 * @author ljc
 * @date 2020/12/15 15:18
 */
@Configuration
@Slf4j
public class TokenHeadFilter implements Filter{

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {


        if (HttpMethod.GET.name().equals(((HttpServletRequest) servletRequest).getMethod())){
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) servletRequest) {
                @Override
                public BufferedReader getReader() throws IOException {
                    return new BufferedReader(new InputStreamReader(getInputStream()));
                }

                @Override
                public ServletInputStream getInputStream() throws IOException {
                    // 转为 ServletInputStream
                    HttpServletRequest request = (HttpServletRequest) servletRequest;
                    ServletInputStream inputStream = request.getInputStream();
                    // 获取头
                    String accessToken = request.getHeader(HttpConstant.REQUEST_HEAD_TOKEN);
                    // 如果token不为空 则注入Token
                    if (null != accessToken) {

                        // 设置byte大小并接收
                        byte[] b = new byte[1024];
                        int lens = -1;
                        StringBuilder stringBuilder = new StringBuilder();
                        while ((lens = inputStream.read(b)) > 0) {
                            stringBuilder.append(new String(b, 0, lens));
                        }

                        try {
                            // 读取前端发送的body数据 转为 JSONObject
                            if (StringUtils.isBlank(stringBuilder)) {
                                stringBuilder.append("{}");
                            }
                            JSONObject jsonObject = JSONObject.parseObject(stringBuilder.toString());
                            // 注入Token
                            jsonObject.put(HttpConstant.ENTITY_HEAD_TOKEN, accessToken);
                            Long userId = JwtUtil.getUserId(accessToken);
                            String userJson = stringRedisTemplate.opsForValue().get(RedisConstant.SHIRO_USER + userId);
                            if (StringUtils.isNotBlank(userJson)) {
                                UserDTO userDTO = JSONUtil.toBean(userJson, UserDTO.class);
                                jsonObject.put(HttpConstant.ENTITY_USER_DTO, userDTO);
                            }
                            // 重新转为Json
                            String json = jsonObject.toJSONString();
                            // 自定义inputStream
                            InputStream sourceStream = new ByteArrayInputStream(json.getBytes());

                            /**
                             * 返回自定义包装后inputStream
                             */
                            inputStream = new ServletInputStream() {
                                @Override
                                public int read() throws IOException {
                                    return sourceStream.read();
                                }

                                /**
                                 * 设置未读取结束
                                 * @return
                                 */
                                @Override
                                public boolean isFinished() {
                                    return false;
                                }

                                /**
                                 * 设置未读取
                                 * @return
                                 */
                                @Override
                                public boolean isReady() {
                                    return false;
                                }

                                @Override
                                public void setReadListener(ReadListener readListener) {
                                }
                            };


                        } catch (Exception e) {
                            log.error("注入Token失败: {}" + e.getMessage());
                            throw new BusinessException(e.getMessage());
                        }

                    }
                    return inputStream;
                }

            };

            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }

}
